//===- Hello.cpp - Example code from "Writing an LLVM Pass" ---------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements two versions of the LLVM "Hello World" pass described
// in docs/WritingAnLLVMPass.html
//
//===----------------------------------------------------------------------===//

//#define DEBUG_TYPE "hello"
#include "llvm/Module.h"
#include "llvm/Pass.h"
#include "llvm/Function.h"
#include "llvm/BasicBlock.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/InstIterator.h"
#include "llvm/Type.h"
#include "llvm/Value.h"
#include "llvm/Instruction.h"
#include "llvm/Instructions.h"

#include "llvm/InstrTypes.h"
#include "llvm/GlobalValue.h"
#include "llvm/GlobalVariable.h"
#include "stdio.h"
#include"string.h"
#include "llvm/Support/Debug.h"
#include "map"
#include "vector"
#include "fstream"
#include "iostream"

//#include "OLIVE/x_array.h"
//#include "OLIVE/tree.h"
//#include "OLIVE/x_array.h"
//#include "OLIVE/tree.int"
//#include "OLIVE/no_name.h"
//#include "OLIVE/mybrg.c"
#include "OLIVE/mybrg2.c"



//#include "llvm/ADT/ValueMap.h"
using namespace std;
//#include "llvm/ADT/Statistic.h"
using namespace llvm;

map<string , Instruction* > hashtable;
//map<long, Instruction*> ::iterator it;
map< Instruction*, Value*> valnumtable;
map< Instruction *, int> tempregister;
map<Value*, Value*> nametable1;
map<Value*, bool> nametable2;
map<Value*,Value*>pointsto;


map<int,Value*> regcontents;


map<Value*,int> regdescriptor;
map<Value*,int> memdescriptor;
map<Value*, Value*> beguse;
vector<Value*>sortedenduse;
map<Value*, int> instrnum;
map<Value*, Value*> enduse;

map<Value*, Value*>globals;
map<int, string> registers;
map<int,bool>registerflag;
map<int, string> registersl;
vector<string> argregs;
vector<string>argregsl;
map<Value*,int>activsize;
//int offset = 0;
int localoffset = 0;
int freeregs = 11;
int numregs = 11;
const char* getregname(int i)
{
    return registers.at(i).c_str();
    //return "hello";
}


void reginit()
{



    
      registers[0] = "r10";
       registers[1] = "r11";
        registers[2] = "r12";
         registers[3] = "r13";
          registers[4] = "r14";
           ;
           registers[5] = "rdi";
          registers[6] = "rsi";
          registers[7] = "r15";
           registers[8] = "rcx";
           registers[9] = "r8";
     registers[10] = "r9";


           registers[11] = "rbx";

         registersl[0] = "r8";
     registersl[1] = "r9";
      registersl[2] = "r10";
       registersl[3] = "r11";
        registersl[4] = "r12";
         registersl[5] = "r13";
          registersl[6] = "r14";
           registersl[7] = "r15";
           registerflag[0] = false;
            registerflag[1] = false;
             registerflag[2] = false;
              registerflag[3] = false;
               registerflag[4] = false;
                registerflag[5] = false;
                 registerflag[6] = false;
                  registerflag[7] = false;
                  registerflag[8] = false;
               registerflag[9] = false;
                registerflag[10] = false;
                 //registerflag[11] = false;
                 // registerflag[7] = false;
                  // registerflag[0] = false;



}
void argreginit()
{

    //EAX, EBX, ECX, EDX, ESI, EDI, EBP, and ESP
    // argregs.push_back("rax");
    argregs.push_back("rdi");
    argregs.push_back("rsi");
    argregs.push_back("rdx");
     argregs.push_back("rcx");

    argregs.push_back("r8");
    argregs.push_back("r9");

    //argregsl.push_back("rax");
       argregsl.push_back("rdi");
    argregsl.push_back("rsi");
    argregsl.push_back("rdx");
     argregsl.push_back("rcx");
       argregsl.push_back("r8");
    argregsl.push_back("r9");
    

/*
    argregs.push_back("edi");
    argregs.push_back("esi");
    argregs.push_back("edx");
    argregs.push_back("ecx");
    argregs.push_back("r8d");
    argregs.push_back("r9d");

    argregsl.push_back("rdi");
    argregsl.push_back("rsi");
    argregsl.push_back("rdx");
    argregsl.push_back("rcx");
    argregsl.push_back("r8");
    argregsl.push_back("r9");*/

}
int last;


void copyglobals()
{
    for(map<Value*, Value*>::iterator it = globals.begin(); it != globals.end(); it++) {
        nametable1[it->first] = it->second;
    }
}
int getmem(Value* val)
{
    if(memdescriptor.find(val) == memdescriptor.end())
        return NULL;
    return memdescriptor[val];
}
bool isolder(Value*a, Value*b)
{
    return a>b;
}


void expireold(Value *val)
{
    for(map<Value*,int>::iterator it = regdescriptor.begin(); it != regdescriptor.end(); it++)
    {
        if(isolder(enduse[it->first],val))
        {
            registerflag[it->second] = false;
            //
            int meml = memdescriptor[it->first];
            fprintf(f, "\tmovq\t%%%s ,-%d(%%rbp)\n",getregname(it->second),meml);
            fprintf(stderr, "\noldvalue expired\n\tmovq\t%%%s ,-%d(%%rbp)\n",getregname(it->second),meml);
            regcontents.erase(it->second);
            regdescriptor.erase(it->first);
            freeregs++;

        }

    }
}
void putmem(Value *val)
{
    if(memdescriptor.find(val) == memdescriptor.end())
    {
        memdescriptor[val] = offset;
        offset +=8;
    }
}

int spill(Value* val)
{
    bool start = true;
    Value* lowestend = 0;
    int returnval;
    for(map<Value*,int>::iterator it = regdescriptor.begin(); it != regdescriptor.end(); it++)
    {
        if(start)
        {
            lowestend = it->first;
            start = false;
            continue;
        }

        if(isolder(enduse[it->first],enduse[lowestend]))
        {
            lowestend = it->first;

        }
    }
        returnval = regdescriptor[lowestend];

         int meml = memdescriptor[regcontents[returnval]];
         {

         }
            fprintf(f, "\tmovq\t%%%s ,-%d(%%rbp)\n",getregname(returnval),meml);
            fprintf(stderr, "\nregister spilled\n\tmovq\t%%%s ,-%d(%%rbp)\n",getregname(returnval),meml);

            putmem(val);//
            regcontents[returnval] = val;
        regdescriptor.erase(lowestend);
        regdescriptor[val] = returnval;
        registerflag[returnval] = true;
        return returnval; 

}


void spillthis(int reg)
{

    if(regcontents.find(reg) != regcontents.end())
    {
        putmem(regcontents[reg]);

        if(regdescriptor.find(regcontents[reg]) != regdescriptor.end())
        {
              int meml = memdescriptor[regcontents[reg]];
             regdescriptor.erase(regcontents[reg]);
             fprintf(f, "\tmovq\t%%%s ,-%d(%%rbp)\n",getregname(reg),meml);
            fprintf(stderr, "\nregister spilled\n\tmovq\t%%%s ,-%d(%%rbp)\n",getregname(reg),meml);

        }
         regcontents.erase(reg);
         registerflag[reg] = false;
         freeregs++;
    }
}

int getoldreg(Value * val)
{
     if(regdescriptor.find(val) != regdescriptor.end())
        return regdescriptor[val];
     return -1;
}





int getreg(Value* val)
{
    if(regdescriptor.find(val) != regdescriptor.end())
        return regdescriptor[val];

    if(memdescriptor.find(val) != memdescriptor.end())
    {
        fprintf(f,"\tmovq\t-%d(%%rbp), %%%s\n",memdescriptor[val],getregname(11));
        return 11;
    }


    if(freeregs == 0)
    {
        expireold(val);
    }
    if(freeregs == 0)
    {
       return spill(val);    
    }
    for(int i = 0; i < numregs; i++)
    {
        if(!registerflag[i])
        {
            putmem(val);//All values in registers are also in memory
            regdescriptor[val] = i;
            registerflag[i] = true;
            freeregs--;
            regcontents[i] = val;
            return i;
        }

    }
    return -1;
    
    
}


int getsize(const Type *ty)
{
    int size = 0;
    if(ty->isArrayTy())
    {
        size = 1;
        size *= ((const ArrayType*)ty) ->getNumElements();
        ty = ((const ArrayType*)ty) ->getElementType();
        size *= getsize(ty);
        
    }
    else if(ty ->isStructTy())
    {
        int num = ((const StructType*)ty) ->getNumContainedTypes();
        int j;
        for(j = 0; j < num; j++)
        {
            size += getsize(((const StructType*)ty) ->getContainedType(j));
        }
    }
    

    else if(ty->isIntegerTy())
    {
            size = 8;
    }
    else if(ty ->isPointerTy())
    {
        size = 8;
    }
    else //if(ty ->isSingleValueType())
    {

        errs()<<"typeid "<<*ty<<"\n";
        //exit(0);
         int num = ((const StructType*)ty) ->getNumContainedTypes();
        int j,usize;
        size = 0;
        for(j = 0; j < num; j++)
        {
            usize = getsize(((const StructType*)ty) ->getContainedType(j));
            if(usize > size)
            {
                size = usize;

            }
        }
    }
    errs()<<"\n\n\tsize = "<<size<<"\n\n";


    return size;

}


    int getnumelem(Value *ac)
    {
       // exit(0);
       // return 9;
       // const Type *aci;
        int c = 0;
       // if(isa<Instruction>(ac)){




Instruction *aci = (Instruction*)ac;
//errs()<<*aci<<"\ttype=\t"<<*aci->getType()<<"\t"<<aci->getType()-><<"\n";
//if(aci->getOperand(0)->getType()->isArrayTy())
//{
//    const Type * ty = aci->getOperand(0)->getType();
//    errs()<<"\n\n\n\n\nhere\n\n\n";
//    return ty->getScalarSizeInBits();
//}
while(isa<GetElementPtrInst>(aci))
{
    aci = (Instruction*)aci->getOperand(0);
    c++;
}

        //}
        //else
          //  return 8;
 //unsigned int num = aci ->getNumElements();
AllocaInst* acci = (AllocaInst*)aci;
         const Type * typ = acci->getAllocatedType();
         int size = 1, tsize = 8;
        // errs()<<"typ16 id = "<<aci ->getTypeID()<<"\t"<<*ac<<"\n";
         while(typ ->isArrayTy())
         {
             //errs ()<<aci ->getNumContainedTypes();
            unsigned int num = ((const ArrayType*)typ) ->getNumElements();
            if(c == 0)
            {
            size *= num;
            }
            else
            {
                c--;
            }
            tsize *= num;
            // errs()<<"\nnum  = "<<num<<"\n";
             //Value* at = aci ->getArraySize();
             //errs() <<"\n\t\tArray here\t"<<*at<<"\t"<<*ins<<"\n";
             typ = ((const ArrayType*)typ) ->getElementType();
           //  typ->
         }
          if(typ ->isStructTy())
         {
              const StructType *st = ((const StructType*) typ);
              size *= getsize(typ);
//              int num = st->getNumContainedTypes();
//              int j;
//              for(j = 0; j < num; j++)
//              {
//
//
//               size *=   st->getContainedType(j)->getScalarSizeInBits();
//
//
//              }
         }
         if(typ ->isIntegerTy())
         {
             size *= 8;
         }


         errs()<<"\n\t"<<*ac<<"\n no. of elements  = "<<size<<"\ttsize = "<<tsize<<"\n";
         return size;
    }




int putreg(Value* val)
{
    return -1;

}


int isalreadyinmemory(llvm::Value* val)
{
    if(memdescriptor.find(val) != memdescriptor.end())
    {
        return memdescriptor[val];
    }
    else
        return -1;
}
int isalreadyinregister(llvm::Value* val)
{
    if(regdescriptor.find(val) != regdescriptor.end())
    {
        if(regcontents[regdescriptor[val]] != val)
        {
            errs()<<"\n\tregister content invalid\n";
        }
        return regdescriptor[val];
    }
    else
        return -1;
}

void fixmemory(Value* val)
{
    if(regdescriptor.find(val) != regdescriptor.end())
    {
        int reg1 = regdescriptor[val];
        if(regcontents[reg1] != val)
        {
            errs()<<"\n\t\tRegister content error\n";
        }
        else
        {
        int meml = memdescriptor[val];
        fprintf(stderr,"\n\nMemory fixed for -%d(%%rbp)\n",meml);
        fprintf(f, "\tmovq\t%%%s ,-%d(%%rbp)\n",getregname(reg1),meml);
       // exit(0);
        }
    }
}





//STATISTIC(HelloCounter, "Counts number of functions greeted");

namespace {
    // Hello - The first implementation, without getAnalysisUsage.
    /*Value* find(map< Instruction*, Value*> valnumtable,Value*val) {
        for(map::const_iterator i = valnumtable.begin(); i != valnumtable.end(); i++) {
            if(i->second == val)
                return i->first;
        }
        return valnumtable.end();


    }*/
 

    char* fixup(const char * str)
    {
        char * name = (char*)malloc(2*strlen(str)+1);

        unsigned i;
        //name[0] = '\0';
       // errs()<<"\n\tstrlen = "<<strlen(str)<<"\n";
        //errs()<<"hello\n";
        for( i = 0; i<strlen(str); i++)
        {
            name[i] = str[i];
        }
        name[i] = 0;
        unsigned int j = strlen(name);
        for(i = 0; i< j; i++)
        {
            //fprintf(stderr,"\n%d\t%d\n",i,name[i]);
           // errs()<<"j = "<<j<<"\n";
            if(name[i] == '\n')
            {
               // errs()<<"\n\n\tyyy\n";

                
                //errs()<<"bf strcpy"<<name<<"\n";
                for(unsigned k = j; k>i; k--)
                {
                    name[k+1] = name[k];
                }
                //strcpy(name+i+3,name+i+1);
                 
                 name[i] = '\\';
                name[i+1] = 'n';
                //name[i+2] = 'A';
                //errs()<<"af strcpy"<<name<<"\n";
                j++;
                i++;
            }
            if(name[i] == '\t')
            {
               // errs()<<"\n\n\tyyy\n";
for(unsigned k = j; k>i; k--)
                {
                    name[k+1] = name[k];
                }
                
                name[i] = '\\';
                name[i+1] = 't';
                //name[i+2] = '9';
                j++;
                i++;
            }
            if(name[i] == '%' && (name[i+1] == 'd' || name[i+1] == 'u'))
            {
               // errs()<<"\n\n\tyyy\n";
                for(unsigned k = j; k>i; k--)
                {
                    name[k+1] = name[k];
                }


                name[i+1] = 'l';
                //name[i+2] = '9';
                j++;
                i++;
            }



        }
        //errs()<<"\n\tFormatted string = "<<name<<"\n";
        return name;
    }




    void sort(string  *abc) {
        const char * st = abc ->c_str();
        unsigned i;
        char * str = new char[1000];
        for( i = 0; i < abc -> length(); i++) {
            str[i] = st[i];
        }
        str[i] = '\0';
        char temp;
        for (i = 0; i < abc ->length(); i++) {
            for(unsigned  j = 0; j < abc -> length() - i - 1; j++) {
                if(str[j] > str[j+1]) {
                  temp = str[j];
                  str[j] = str[j+1];
                  str[j+1] = temp;
                }
            }
        }
        abc->clear();
        abc->append(str);
    }


    Tree generatetree(Instruction * ins) {
        Tree t;
        if(isa<ConstantInt>(ins)) {
            //errs()<<"\n\n....constant int\n\n\n";
           //  errs()<<"constant\n\n";
            t = tree(CNSTINT,0,0);
            t->val = ((ConstantInt*)ins) ->getSExtValue();
            errs()<<"constant val = "<<t->val<<"\n";
           
                return t;
        }

        if (isa<BinaryOperator> (ins)) {
            t = (Tree) malloc(sizeof *t);
        
            if (strcmp(ins ->getOpcodeName(), "add") == 0) {
                t->op = ADD;
            } else if (strcmp(ins ->getOpcodeName(), "sub") == 0) {
                t->op = SUB;
            } else if (strcmp(ins ->getOpcodeName(), "mul") == 0) {
                t->op = MUL;
            } else if (strcmp(ins ->getOpcodeName(), "udiv") == 0) {
                t->op = DIV;
            }
            else if (strcmp(ins ->getOpcodeName(), "sdiv") == 0) {
                t->op = SDIV;
            }

            else if (strcmp(ins ->getOpcodeName(), "ashr") == 0) {
                t->op = ASR;

            }

            else if (strcmp(ins ->getOpcodeName(), "lshr") == 0) {
                t->op = SHR;
            }
            else if (strcmp(ins ->getOpcodeName(), "shl") == 0) {
                t->op = SL;
            }

             else if (strcmp(ins ->getOpcodeName(), "and") == 0) {
                t->op = AND;
            }
             else if (strcmp(ins ->getOpcodeName(), "or") == 0) {
                t->op = OR;
            }
              else if (strcmp(ins ->getOpcodeName(), "xor") == 0) {
                t->op = XOR;
            }



            t ->kids [0] = generatetree((Instruction*) ins ->getOperand(0));
            t ->kids [1] = generatetree((Instruction*) ins ->getOperand(1));
            t-> val = (unsigned long)ins;
            t->x.state = 0;


            return t;
        }


        switch(ins ->getOpcode()){
           
            case 27://LOAD
            {
                // errs()<<"Load\n\n";
                 t = (Tree) malloc(sizeof *t);
                   t->op = LOAD;

                   // errs()<<*(Instruction*)ins ->getOperand(0)<<"\n\n";
                 t->kids[0] = generatetree((Instruction*)ins ->getOperand(0));
                
                 t ->kids[1] = 0;

                 t-> val = (unsigned long)ins;
                 t->x.state = 0;
                 return t;
            }
            case 26://ALLOCA
            {
                //  errs()<<"\n\n....alloca\n\n\n";
                // errs()<<"alloca\n\n";

               /* if (isa<PointerType > (ins ->getType()))
                {
                        t = tree(ALLOCAPTR, 0, 0);
                        t ->val = (unsigned long) ins;
                        //errs()<<"\t\tt->val = "<<t->val<<"\n";
                        t -> size = 8;
                    } else */
                    


                    t = tree(ALLOCA, 0, 0);
                            t-> val = (unsigned long) ins;
                            //errs()<<"\t\tt->val = "<<t->val<<"\n";
                            t -> size = 8;
                

                return t;
            }

            case 45://CALL
            {
                t = tree(CALL,0,0);
                t-> val = (unsigned long)ins;
                return t;

            }

            case 29://GEP
            {
                t = (Tree) malloc(sizeof *t);
                t ->op = GEP;
                t ->val = (unsigned long)ins;
                t ->kids[0] = generatetree((Instruction*)ins ->getOperand(0));
                if(ins->getNumOperands() == 3)
                {
                    t ->kids[1] = generatetree((Instruction*)ins ->getOperand(2));
                }
                else
                {
                     t ->kids[1] = generatetree((Instruction*)ins ->getOperand(1));
                }
                return t;
            }
            case 32://bitcast
            {
                return generatetree((Instruction*) ins ->getOperand(0));
            }
             case 31://zextn
            {
                return generatetree((Instruction*) ins ->getOperand(0));
            }
            case 30://trunc
            {
                //errs()<<"\n\t"<<*ins ->getOperand(0)<<"\t"<<((Instruction*)ins->getOperand(0))->getOpcode()<<"\n";
                return generatetree((Instruction*) ins ->getOperand(0));
            }
            case 39://ptr to int
            {
                // errs()<<"\n\t"<<*ins ->getOperand(0)<<"\t"<<((Instruction*)ins->getOperand(0))->getOpcode()<<"\n";
                return generatetree((Instruction*) ins ->getOperand(0));
            }
            case 41://bitcast 8 to 32
            {
                // errs()<<"\n\t"<<*ins ->getOperand(0)<<"\t"<<((Instruction*)ins->getOperand(0))->getOpcode()<<"\n";
                return generatetree((Instruction*) ins ->getOperand(0));
            }
            default:
            {

 
                if(isa<GlobalVariable>(ins) )
                {
                    //exit(0);
                    t = tree(GLOBAL, 0, 0);
                            //errs()<< *globals[(Value*)ins];
                           // if()
                            GlobalVariable* gb = (GlobalVariable*)ins;
                               // t -> val = (long)globals[(Value*)ins];
                              //  errs() <<"\n"<<gb->getValueName()->getKey().str();
                                global = (char*)malloc(25);
                                sprintf(global,"$%s",gb->getValueName()->getKey().str().c_str());
                              //  errs()<<"\n\n";
                                //exit(0);
                                t->val = (long)global;
                                fprintf(stderr,"%s",global);
                                
                               // t -> val = dyn_cast<ConstantInt>(globals[(Value*)ins])->
                           
                           // errs()<<"\t\tt->val = "<<t->val<<"\n";
                            t -> size = 8;
                           // exit(0);

                return t;


                }
                //errs()<<ins->getOpcode()<<"\n\n";
                else
                {
                    t = tree(ARGALLOC, 0, 0);
                            t-> val = (unsigned long) ins;
                            //errs()<<"\t\tt->val = "<<t->val<<"\n";
                            t -> size = 8;
                            
                return t;
                }
                errs()<<"Undefined Instruction\t\n";
                errs()<<*ins<<"\t\n";
                errs()<<ins->getOpcode()<<"\n\n";
                exit(0);
            }
        }
    }



    struct Valuenum : public ModulePass {
        static char ID;

        Valuenum() : ModulePass(ID) {
        }


        virtual bool runOnBasicBlockLive(BasicBlock & BB) {




                for (BasicBlock::iterator i =  BB.end(); i != BB.begin(); i--) {
                    if( i == BB.end())
                        continue;
                    //errs()<< "Instruction \t"<<i<<"\n";
                    int num = i ->getNumOperands();
                   
                    for(int j = 0; j < num; j++) {
                      //  errs()<<*i;
                        if(isa<Instruction>( i->getOperand(j) )) {

                           
                             Value* ins =  i->getOperand(j);
                   
                            if(enduse.find(ins) == enduse.end()) {
                                enduse[ins] = i;
                            }
                            beguse[ins] = i;

                        }
                    }


             }
                 for (BasicBlock::iterator i = BB.begin(); ; ) {
                   
                    int num = i ->getNumOperands();
                   
                    for(int j = 0; j < num; j++) {
                      //  errs()<<*i;
                        if(isa<Instruction>( i->getOperand(j) )) {

                           
                             Value* ins =  i->getOperand(j);
                   
                            if(enduse.find(ins) == enduse.end()) {
                                enduse[ins] =  i;
                            }
                            beguse[ins] = i;

                        }
                    }
                    break;

             }



             return false;
        }

        void pushall() {


            for (unsigned int i = 0; i < registers.size(); i++) {
                fprintf(f, "\tpushq\t%%%s\n", registers[i].c_str());

            }
            for (unsigned int i = 0; i < registers.size(); i++) {
              //  fprintf(f, "\tpushq\t%%%s\n", registers[i].c_str());

            }

        }
        
        void popall() 
        {
             for (int i = registers.size()-1; i>=0; i--) {
                //fprintf(f, "\tpopq\t%%%s\n", registers[i].c_str());

            }
              for (int i = registers.size()-1; i>=0; i--) {
                fprintf(f, "\tpopq\t%%%s\n", registers[i].c_str());

            }
             
             
        }

        virtual bool runOnBasicBlockPrint(BasicBlock & BB)
        {
            for (BasicBlock::iterator i = BB.begin(); i != BB.end(); i++) {
                errs()<<"\t"<<*i<<"\n";
            }
            return false;
        }

         virtual bool runOnBasicBlockOut(BasicBlock & BB) {

            
           // t = tree(STORE,tree(ADDRLP, 0, 0),tree(ADDI,tree(CVCI, tree(INDIRC, tree(ADDRLP, 0, 0), 0), 0),(t = tree(CNSTI, 0, 0), t->val = 4, t)));
             for (BasicBlock::iterator i = BB.begin(); i != BB.end(); i++) {

                // errs()<<"\n\t"<<*i<<"\n";
                 

                 if(i ->getOpcode() == 26)//Alloca
                 {
                     //errs()<<"\tmem value value = "<<i<<"\n";
                     if(memdescriptor.find(i) == memdescriptor.end())
                     {
                         Instruction * ins = (Instruction*) i;
                         const Type *aci = ((AllocaInst*)ins)->getAllocatedType() ;
 //unsigned int num = aci ->getNumElements();
                        //const Type * typ = aci->getAllocatedType();
                         int size = getsize(aci);
                      //   if(aci ->isArrayTy())
                        //     size *=2;
//                         bool flag = true;
//                         while(aci ->isArrayTy())
//                         {
//                             if(flag)
//                             {
//                                 size *= 1;
//                                 flag = false;
//                             }
//                             //errs ()<<aci ->getNumContainedTypes();
//                            unsigned int num = ((const ArrayType*)aci) ->getNumElements();
//                            size *= num;
//                            // errs()<<"\nnum  = "<<num<<"\n";
//                             //Value* at = aci ->getArraySize();
//                             //errs() <<"\n\t\tArray here\t"<<*at<<"\t"<<*ins<<"\n";
//                             aci = ((const ArrayType*)aci) ->getElementType();
//                           //  typ->
//                         }
//                          if(aci ->isStructTy())
//                         {
//                              StructType *st = ((StructType*) aci);
//                              int num = st->getNumContainedTypes();
//                              int j;
//                              for(j = 0; j < num; j++)
//                              {
//
//                               size *=   st->getContainedType(j)->getScalarSizeInBits();
//
//
//                              }
//                         }
//                         else//if(aci ->isIntegerTy())
//                         {
//                             size *= 8;
//                         }




                      //   errs()<<"\n\tSize = "<<size<<"\n\n";
                         //long int size = ((ConstantInt*) siz) ->getSExtValue();
                         //errs()<<"\n\n\tAlloca size = "<<size<<"\n";
                         memdescriptor[i] = offset;
                         //if(isa<PointerType>(i->getType()))
                         {
                           //  errs()<<"\n\t\tPointer found\n";
                             offset += size;//Pointer size is 8
                         }

                        
                        // else
                         {
                          //  offset += 8;// int size is 4
                         }

                     
                     }
                }


                 if (i->getOpcode() == 45)//Call
                {
                    //errs() << ";executing call" << "\n";

                    CallInst* ci = dyn_cast<CallInst > (i);
                    pushall();
                    int numargs = ci->getNumArgOperands();
                    int j;
                   // errs() << "No. of args = " << numargs << "\n";
                    int sp = (numargs-7) * 8;
                    int argrsize = 6;
                    for (j = numargs-1; j >=0; j--) {
                        Tree t, t1;

                        if ((valnumtable.find((Instruction*) ci->getArgOperand(j)) != valnumtable.end()) || (isa<BinaryOperator>(ci ->getArgOperand(j))) ) {//Locals
                            t1 = generatetree((Instruction*)ci->getOperand(j));
                            t = tree(ARGS, t1, 0);
                            gen(t);
                            if(((Instruction*)ci->getOperand(j))->getOpcode() == 32)
                            {
                                //fprintf(f,)
                            }
                             if (j < argrsize) {
                                 fprintf(f, "\tmovq\t%%%s, %%%s\n","rax",argregs.at(j).c_str());
                                 fprintf(stderr, "\tmovq\t%%%s, %%%s\n","rax",argregs.at(j).c_str());
                                 
                                 //freeregs--;
                                 if(j != 2)
                                 {
                                 spillthis(j+5);
                                 //regcontents[j+5] = ci->getOperand(j);
                                 //registerflag[j+5] = true;
                                 }

                               // fprintf(f, "\tmovq\t-%d(%%rbp), %%%s\n", memdescriptor[valnumtable[(Instruction*) ci->getArgOperand(j)]], argregs.at(j).c_str());
                            } else {
                                //            movq	-40(%rbp), %rsi
                                //movq	%rsi, (%rsp)
                               // fprintf(f, "\tmovq\t-%d(%%rbp), %%%s\n", memdescriptor[valnumtable[(Instruction*) ci->getArgOperand(j)]], "rax");
                                fprintf(f, "\tmovq\t%%%s, %d(%%%s)\n", "rax", sp, "rsp");
                                sp -= 8;



                            }

                        } else//Globals, Constants and operand arguments
                        {

                              if(isa<ConstantInt> (ci ->getArgOperand(j)))//Constant int
                              {
                                int value = ((ConstantInt*) ci->getArgOperand(j)) ->getSExtValue();
                                if (j < argrsize) {
                                    fprintf(f, "\tmovq\t$%d, %%%s\n", value, argregs.at(j).c_str());
                                } else {
                                    fprintf(f, "\tmovq\t$%d, %%%s\n", value, "rax");
                                    fprintf(f, "\tmovq\t%%%s, %d(%%%s)\n", "rax", sp, "rsp");
                                    sp -= 8;
                                }

                            }



                            //string
                              else if (isa<PointerType > (ci ->getArgOperand(j)->getType())) {

                                //if(dyn_cast<GetElementPtrInst> (ci ->getArgOperand(j)))

                                GetElementPtrInst* gep = (GetElementPtrInst*) (ci ->getArgOperand(j));
                                if (gep ->getNumOperands() > 2) {
                                    if (j < argrsize) {
                                        fprintf(f, "\tmovq\t$%s, %%%s\n", gep->getOperand(0)->getValueName()->getKey().str().c_str(), argregs.at(j).c_str());
                                    } else {
                                        fprintf(f, "\tmovq\t$%s, %%%s\n", gep->getOperand(0)->getValueName()->getKey().str().c_str(), "rax");
                                        fprintf(f, "\tmovq\t%%%s, %d(%%%s)\n", "rax", sp, "rsp");
                                        sp -= 8;
                                    }

                                } else {
                                    //leaq	-4(%rbp), %rdx
                                    // errs()<<"\n\t"<<*ci ->getArgOperand(j);
                                    //errs()<<"\n\t"<<*valnumtable[(Instruction*)ci ->getArgOperand(j)];
                                    //  errs()<<"\n\tgep "<<gep->getOperand(1)<<"\t"<<*ci ->getArgOperand(j)<<"\n";

                                   // t1 = generatetree((Instruction*)ci->getOperand(j));
                                    //t = tree(ARGS, t1, 0);
                                    //gen(t);
                                    if(isa<AllocaInst> (ci ->getArgOperand(j)))
                                    {
                                        fixmemory(ci ->getArgOperand(j));
                                        if (j < argrsize) {

                                        fprintf(f, "\tleaq\t-%d(%%rbp), %%%s\n",memdescriptor[ci ->getArgOperand(j)],argregs.at(j).c_str());
                                        //fprintf(f, "\tleaq\t-%d(%%rbp), %%%s\n", memdescriptor[ci ->getArgOperand(j)], argregsl.at(j).c_str());
                                    } else {
                                       // fprintf(f, "\tleaq\t-%d(%%rbp), %%%s\n", memdescriptor[ci ->getArgOperand(j)], argregsl.at(j).c_str());
                                        //fprintf(f, "\tleaq\t-%d(%%rbp), %%%s\n", memdescriptor[ci ->getArgOperand(j)], "rsi");
                                          fprintf(f, "\tleaq\t-%d(%%rbp), %%%s\n", memdescriptor[ci ->getArgOperand(j)], "rax");

                                            fprintf(f, "\tleaq\t%%%s, %d(%%%s)\n", "rax", sp, "rsp");
                                        sp -= 8;
                                    }

                                    }
                                    else
                                    {
                                        errs()<<"\n\t\tNew argument\n";
                                    }

                                }

                            }
                          

                        }
                        if(j < argrsize)
                        fprintf(f,"\tpushq\t%%%s\n",argregs.at(j).c_str());
                    }
                    int k = numargs;
                    if(k > 6)
                        k = 6;
                    for(j = 0; j < k; j++)
                    {
                       fprintf(f,"\tpopq\t%%%s\n",argregs.at(j).c_str());
                    }



                    if (ci->getCalledFunction()->getNameStr() == "printf"
                            || ci->getCalledFunction()->getNameStr() == "puts"
                            ) {

                        // fprintf(f, "\tmovq\t%%edi, %%rax\n");
                        //  movq	%ecx, %rsi
                        //fprintf(f, "\tmovq\t%%rdx, %%rsi\n"); //,argregs.at(numargs-1).c_str());
                        //fprintf(f, "\tmovq\t%%rbx0 %%rdi\n");
                        fprintf(f, "\tmovq\t$0, %%rax\n");
                        fprintf(f, "\tcall\tprintf\n");
                    }
                    // errs()<<"\n\tCalled function\t"<<ci->getCalledFunction()->getNameStr()<<"\n";
                    else if (!strcmp(ci->getCalledFunction()->getNameStr().c_str() + 1, "__isoc99_scanf")) {

                        //movq	%rcx, %rsi
                        //fprintf(f, "\tmovq\t%%edi, %%rax\n");
                        //fprintf(f, "\tmovq\t%%rdx, %%rsi\n"); //argregsl.at(numargs-1).c_str());
                        //fprintf(f, "\tmovq\t%%rbx, %%rdi\n");
                        fprintf(f, "\tmovq\t$0, %%rax\n");
                        fprintf(f, "\tcall\t__isoc99_scanf\n");
                    }
                    else
                    {
                       //fprintf(f, "\tmovq\t$0, %%rax\n");
                        fprintf(f, "\tcall\t%s\n",ci->getCalledFunction()->getNameStr().c_str()); 
                    }





                    popall();

                    int regs = getreg(i);
                    fprintf(f, "\tmovq\t%%rax, %%%s\n", getregname(regs));
                    fixmemory(regcontents[regs]);



                }

                 if(i ->getOpcode() == 42)//ICMP
                 {
                     Tree t,t1,t2;
                      t1 = generatetree((Instruction*)i->getOperand(0));
                       t2 = generatetree((Instruction*)i->getOperand(1));
                        t = tree(COMP,t1,t2);
                          gen(t);
                 }




                 if(i->getOpcode() == 28) //Store
                 {
                    Tree t;
                     //t = tree(STORE,tree(ADDRLP, 0, 0),tree(ADDI,tree(CVCI, tree(INDIRC, tree(ADDRLP, 0, 0), 0), 0),(t = tree(CNSTI, 0, 0), t->val = 4, t)));
                     //t = tree(STORE,tree(GIVEMEM,0,0),0);
                 /*   t = tree(STORE,
                            tree(CNSTINT,0,0),
                                tree(ALLOCA,0,0)
                                    
                             );*/
                    /*  t = tree(STORE,
                            tree(LOAD,
                                        tree(ALLOCA,0,0),0),
                                tree(ALLOCA,0,0)
                                    
                             );*/

                   //if(((Instruction*)(i->getOperand(1)))->getOpcode() == 26)//Alloca
                   
                       Tree t1,t2;
                      // errs()<<"Store\n\n";
                       t1 = generatetree((Instruction*)i->getOperand(0));
                       t2 = generatetree((Instruction*)i->getOperand(1));
                      // t2 = tree(ALLOCA,0,0);
                      // errs()<<"Store children left\t"<<t1->op<<"\t"<<t1->kids[0]->op<<"\t"<<t1->kids[1]<<"\t"<<STORE<<"\n\n";
                      //  errs()<<"Store children from t left\t"<<t->kids[0]->op<<"\t"<<t->kids[0]->kids[0]->op<<"\t"<<t->kids[0]->kids[1]<<"\t"<<STORE<<"\n\n";
                       // errs()<<"Store children right\t"<<t2->op<<"\t"<<STORE<<"\n\n";
                      t = tree(STORE,t1,t2);
                      
                      
                   
                 /*  else {
                        errs()<<"Store R\n\n";
                     t = tree(STORER,generatetree((Instruction*)i->getOperand(0)),generatetree((Instruction*)i->getOperand(1)));
                     
                   }*/
                    // errs()<<"Store\n\n";
                   // t = generatetree((Instruction*)i) ;
                     //t = tree(ALLOCA,0,0);
                     gen(t);
                    // exit(0);
                 }

                 if(i ->getOpcode() == 2)//Branch
                 {

                     if(i ->getNumOperands() == 1)//Unconditional Jump
                     {
                         fprintf(f,"\tJMP\t.%s%s\n",i->getOperand(0)->getNameStr().c_str(),i->getParent()->getParent()->getNameStr().c_str());
                    } else {
                        int cas = ((ICmpInst*) i->getOperand(0))->getPredicate();
                        //errs()<<*(i->getOperand(1))<<"\n";
                        switch (cas) {

                            case ICmpInst::ICMP_EQ:
                            {
                                fprintf(f, "\tJNE\t.%s%s\n", i->getOperand(1)->getNameStr().c_str(), i->getParent()->getParent()->getNameStr().c_str());
                                fprintf(f, "\tJMP\t.%s%s\n", i->getOperand(2)->getNameStr().c_str(), i->getParent()->getParent()->getNameStr().c_str());
                                break;
                            }

                            case ICmpInst::ICMP_SLE:
                            {
                                fprintf(f, "\tJG\t.%s%s\n", i->getOperand(1)->getNameStr().c_str(), i->getParent()->getParent()->getNameStr().c_str());
                                fprintf(f, "\tJMP\t.%s%s\n", i->getOperand(2)->getNameStr().c_str(), i->getParent()->getParent()->getNameStr().c_str());
                                break;
                            }
                            case ICmpInst::ICMP_ULE:
                            {
                                fprintf(f, "\tJA\t.%s%s\n", i->getOperand(1)->getNameStr().c_str(), i->getParent()->getParent()->getNameStr().c_str());
                                fprintf(f, "\tJMP\t.%s%s\n", i->getOperand(2)->getNameStr().c_str(), i->getParent()->getParent()->getNameStr().c_str());
                                break;
                            }
                            case ICmpInst::ICMP_SGE:
                            {
                                fprintf(f, "\tJL\t.%s%s\n", i->getOperand(1)->getNameStr().c_str(), i->getParent()->getParent()->getNameStr().c_str());
                                fprintf(f, "\tJMP\t.%s%s\n", i->getOperand(2)->getNameStr().c_str(), i->getParent()->getParent()->getNameStr().c_str());
                                break;
                            }
                            case ICmpInst::ICMP_UGE:
                            {
                                fprintf(f, "\tJB\t.%s%s\n", i->getOperand(1)->getNameStr().c_str(), i->getParent()->getParent()->getNameStr().c_str());
                                fprintf(f, "\tJMP\t.%s%s\n", i->getOperand(2)->getNameStr().c_str(), i->getParent()->getParent()->getNameStr().c_str());
                                break;
                            }
                            case ICmpInst::ICMP_SGT:
                            {
                                fprintf(f, "\tJLE\t.%s%s\n", i->getOperand(1)->getNameStr().c_str(), i->getParent()->getParent()->getNameStr().c_str());
                                fprintf(f, "\tJMP\t.%s%s\n", i->getOperand(2)->getNameStr().c_str(), i->getParent()->getParent()->getNameStr().c_str());
                                break;
                            }
                            case ICmpInst::ICMP_UGT:
                            {
                                fprintf(f, "\tJBE\t.%s%s\n", i->getOperand(1)->getNameStr().c_str(), i->getParent()->getParent()->getNameStr().c_str());
                                fprintf(f, "\tJMP\t.%s%s\n", i->getOperand(2)->getNameStr().c_str(), i->getParent()->getParent()->getNameStr().c_str());
                                break;
                            }
                            case ICmpInst::ICMP_SLT:
                            {
                                fprintf(f, "\tJGE\t.%s%s\n", i->getOperand(1)->getNameStr().c_str(), i->getParent()->getParent()->getNameStr().c_str());
                                fprintf(f, "\tJMP\t.%s%s\n", i->getOperand(2)->getNameStr().c_str(), i->getParent()->getParent()->getNameStr().c_str());
                                break;
                            }
                            case ICmpInst::ICMP_ULT:
                            {
                                fprintf(f, "\tJAE\t.%s%s\n", i->getOperand(1)->getNameStr().c_str(), i->getParent()->getParent()->getNameStr().c_str());
                                fprintf(f, "\tJMP\t.%s%s\n", i->getOperand(2)->getNameStr().c_str(), i->getParent()->getParent()->getNameStr().c_str());
                                break;
                            }
                            case ICmpInst::ICMP_NE:
                            {
                                fprintf(f, "\tJE\t.%s%s\n", i->getOperand(1)->getNameStr().c_str(), i->getParent()->getParent()->getNameStr().c_str());
                                fprintf(f, "\tJMP\t.%s%s\n", i->getOperand(2)->getNameStr().c_str(), i->getParent()->getParent()->getNameStr().c_str());
                                break;
                            }
                            default:
                                errs()<<((ICmpInst*) i->getOperand(1))->getPredicate();
                                errs() << "Unknown case in branch\t"<<cas<<"\n";
                                exit(0);



                        }

                    }



                }
                 if(i ->getOpcode() == 1)
                 {
                      Tree t,t1;
                      // errs()<<"Store\n\n";
                       t1 = generatetree((Instruction*)i->getOperand(0));

                      // t2 = tree(ALLOCA,0,0);
                      // errs()<<"Store children left\t"<<t1->op<<"\t"<<t1->kids[0]->op<<"\t"<<t1->kids[1]<<"\t"<<STORE<<"\n\n";
                      //  errs()<<"Store children from t left\t"<<t->kids[0]->op<<"\t"<<t->kids[0]->kids[0]->op<<"\t"<<t->kids[0]->kids[1]<<"\t"<<STORE<<"\n\n";
                       // errs()<<"Store children right\t"<<t2->op<<"\t"<<STORE<<"\n\n";
                      t = tree(RETURN,t1,0);
                      gen(t);
                 }
                 else
                 {
                     //if(i->getOpcode() == 27)//Load
                 {
                     valnumtable[(Instruction*)i] = i->getOperand(0);
                   //  errs()<<"\tload value = "<<i->getOperand(0)<<"\n";
                 }
                 }
                 //else
                 {
                    // errs()<<*i<<"\t"<<i->getOpcode()<<"\n";
                 }
                // errs()<<*i<<"\n";

                //  outfile << *i<<"\n";
                //  fprintf(f,"%s\n",*i);
              //return false;
                 //outfile << "\n";
             }
           //  closefile();
            // gen(t);
            // fclose(f);
             return false;
         }

         void cleartables() {
             hashtable.clear();
             nametable1.clear();
             pointsto.clear();
             copyglobals();
         }

        virtual bool runOnBasicBlock(BasicBlock & BB) {
            static int count;
            errs() << ";count = " << count;
            count++;
            bool flag = false;
            cleartables();
            
            for (BasicBlock::iterator i = BB.begin(); i != BB.end(); i++) {
                localoffset += 8;
                int opcode = i -> getOpcode();
                Instruction *ins = &*i;
                if(flag) {
                    ins->getPrevNode()->eraseFromParent();
                    flag = false;
                }
                DEBUG(errs() << ";................................."<<*i<<"...................\n");
                if (isa<BinaryOperator > (ins)) {
                      string exp;
                      int i;// = new string();
                     // bool cflag = false;
                   // errs() << "*********Binary\n";
                   // long expr = 0;
                    //hashtable[] = ins;
                        //errs()<<"ADD"<<ins->getOpcode()<<"\n\n";
                   // errs() << ";executing binary operand instruction" << "\n";
                   // for (User::op_iterator oi = ins -> op_begin(); oi != ins -> op_end(); oi++) {
                    for (i = 0; i < 2; i++)
                    {
                        Value* v;
                        v = ins->getOperand(i);
                        // expr += (long) v;
                        char temp[200];
                        if (valnumtable.find((Instruction*) v) != valnumtable.end()) {
                            Value *name = valnumtable[(Instruction*) v];
                            //errs() <<";from valtable "<<*name<<"\n";
                            if (nametable1.find(name) == nametable1.end()) {
                               
                            } else {
                                Value* val = nametable1[name];
                                if (isa<ConstantInt > (val)) {
                                    ins ->setOperand(i, val);
                                    
                                }

                            }
                        }
                            v = ins ->getOperand(i);
                            sprintf(temp, "%lu",(unsigned long) v);
                          //  errs()<<" i = "<<i<<" temp = "<<temp<<" v = "<<*v<<"\n";
                            exp.append(temp);
                                
                        if (isa<ConstantInt> (v)) {
                       }

                        // errs() <<"here: "<< v->getNameStr() <<"\t"<<"\n";
                    }
                  //  expr += ins->getOpcode();
                    exp.append(ins ->getOpcodeName());
//calculating compile time constants
                    if (isa<ConstantInt> (ins ->getOperand(0)) && isa<ConstantInt> (ins ->getOperand(1))) {
                     //   valnumtable[ins] =
                        float value;
                        Value* val;

//AllocaInst* ai = new AllocaInst(Type::getInt64Ty(ins->getContext()));
                      //  Instruction *ni = new Instruction();
                         if(strcmp(ins ->getOpcodeName(), "mul") == 0) {



                          value = ((ConstantInt*) (ins ->getOperand(0)))->getSExtValue() * ((ConstantInt*) (ins ->getOperand(1)))->getSExtValue();

                          val =  ConstantInt::getSigned(Type::getInt32Ty(ins->getContext()), value);
                         ins->replaceAllUsesWith(val);
                         flag = true;


                         }else if(strcmp(ins ->getOpcodeName(), "add") == 0) {
                           
                          value = ((ConstantInt*) (ins ->getOperand(0)))->getSExtValue() + ((ConstantInt*) (ins ->getOperand(1)))->getSExtValue();
                           val =  ConstantInt::getSigned(Type::getInt32Ty(ins->getContext()), value);
                         ins->replaceAllUsesWith(val);
                         flag = true;
                         } else  if(strcmp(ins ->getOpcodeName(), "sub") == 0) {
                          value = ((ConstantInt*) (ins ->getOperand(0)))->getSExtValue() - ((ConstantInt*) (ins ->getOperand(1)))->getSExtValue();
                          val =  ConstantInt::getSigned(Type::getInt32Ty(ins->getContext()), value);
                         ins->replaceAllUsesWith(val);
                         flag = true;
                          }else if(strcmp(ins ->getOpcodeName(), "udiv") == 0) {
                          value = ((ConstantInt*) (ins ->getOperand(0)))->getSExtValue() / ((ConstantInt*) (ins ->getOperand(1)))->getSExtValue();
                          val =  ConstantInt::getSigned(Type::getInt32Ty(ins->getContext()), value);
                         ins->replaceAllUsesWith(val);
                         flag = true;
                          }
                         else if(strcmp(ins ->getOpcodeName(), "sdiv") == 0) {
                          value = ((ConstantInt*) (ins ->getOperand(0)))->getSExtValue() / ((ConstantInt*) (ins ->getOperand(1)))->getSExtValue();
                          val =  ConstantInt::getSigned(Type::getInt32Ty(ins->getContext()), value);
                         ins->replaceAllUsesWith(val);
                         flag = true;
                          }
                         else if(strcmp(ins ->getOpcodeName(), "ashr") == 0) {
                          value = ((ConstantInt*) (ins ->getOperand(0)))->getSExtValue() >> ((ConstantInt*) (ins ->getOperand(1)))->getSExtValue();
                          val =  ConstantInt::getSigned(Type::getInt32Ty(ins->getContext()), value);
                         ins->replaceAllUsesWith(val);
                         flag = true;
                          }
                          else if(strcmp(ins ->getOpcodeName(), "shl") == 0) {
                          value = ((ConstantInt*) (ins ->getOperand(0)))->getSExtValue() << ((ConstantInt*) (ins ->getOperand(1)))->getSExtValue();
                           val =  ConstantInt::getSigned(Type::getInt32Ty(ins->getContext()), value);
                         ins->replaceAllUsesWith(val);
                         flag = true;
                          }
                         else if(strcmp(ins ->getOpcodeName(), "and") == 0) {
                          value = ((ConstantInt*) (ins ->getOperand(0)))->getSExtValue() & ((ConstantInt*) (ins ->getOperand(1)))->getSExtValue();
                           val =  ConstantInt::getSigned(Type::getInt32Ty(ins->getContext()), value);
                         ins->replaceAllUsesWith(val);
                         flag = true;
                          }
                          else if(strcmp(ins ->getOpcodeName(), "or") == 0) {
                          value = ((ConstantInt*) (ins ->getOperand(0)))->getSExtValue() | ((ConstantInt*) (ins ->getOperand(1)))->getSExtValue();
                           val =  ConstantInt::getSigned(Type::getInt32Ty(ins->getContext()), value);
                         ins->replaceAllUsesWith(val);
                         flag = true;
                          }
                         else if(strcmp(ins ->getOpcodeName(), "xor") == 0) {
                          value = ((ConstantInt*) (ins ->getOperand(0)))->getSExtValue() ^ ((ConstantInt*) (ins ->getOperand(1)))->getSExtValue();
                           val =  ConstantInt::getSigned(Type::getInt32Ty(ins->getContext()), value);
                         ins->replaceAllUsesWith(val);
                         flag = true;
                          }
                          else{
                              errs()<<";Opcode is "<<ins->getOpcodeName()<<"\n\n";
                          }




                    }



                    if (ins -> isCommutative() == true) {
                        // errs() <<ins ->getOpcodeName()<<" is a commutative expression\n\n";
                        sort(&exp);
                        //expr++;
                    }
                    if (hashtable.find(exp) == hashtable.end()) {
                        //For %x = add %1,%2, %1%2add is not in hashtable. So, add(%1%2add,%x) into hashtable
                        if (exp.length() > 8) {//To skip for arrays
                            hashtable[exp] = ins;

                          //  errs() << "\n\n\t;Expression " << exp << " stored in hashtable\n";
                        } else {
                            //errs() << "\n\n\t;Expression " << exp << " skipped\n";
                        }
                        //  errs ()<<"binary expression = "<<exp<<"\n";
                    } else {
                       //  errs () <<"\n\n**\tfound binary in hash table\t:"<<"exp = "<<exp<<"\t"<<*(hashtable.find(exp)->second)<<"\n";

                        //Common sub expression found. So replcae all occurrence of %x with hashtable[%1%2add]
                        ins->replaceAllUsesWith(hashtable.find(exp)->second);
                        flag = true;
                        //hashtable.erase(exp);
                        // ins->eraseFromParent();
                        //continue;
                        //ins ->removeFromParent();
                         //continue;
                    }
                   // errs() << "\t"<<ins->getOpcodeName()<<"\n";
                    


                } else if (isa <CastInst > (ins)) {
                    errs() << ";**********Cast\n";

                } else if (isa <CmpInst > (ins)) {
                    errs() << ";*************Cmp\n";

                } else if (isa <TerminatorInst > (ins)) {
                    errs() << ";*****************terminator\n";

                }/*  else if(isa<CallInst>(ins)) {
                    errs() <<"**************Call\n";
                }*/
                else {

                    // errs() << "*****************other\n";


                    switch (opcode) {

                        case 2:
                            //errs() << ";executing br" << "\n";
                            break;

                        case 26:
                            //errs() << ";executing alloc" << "\n";
                        {
                             Instruction * ins = (Instruction*) i;
                         const Type *aci = ((AllocaInst*)ins)->getAllocatedType() ;
 //unsigned int num = aci ->getNumElements();
                        //const Type * typ = aci->getAllocatedType();
                         int size = getsize(aci);
                         if(aci ->isArrayTy())
                         {
                            // size *= 2;
                         }
//                         int flag = true;
//
//                         while(aci ->isArrayTy())
//                         {
//                             if(flag)
//                             {
//                                 size *= 1;
//                                 flag = false;
//                             }
//                             //errs ()<<aci ->getNumContainedTypes();
//                            unsigned int num = ((const ArrayType*)aci) ->getNumElements();
//                            size *= num;
//                            // errs()<<"\nnum  = "<<num<<"\n";
//                             //Value* at = aci ->getArraySize();
//                             //errs() <<"\n\t\tArray here\t"<<*at<<"\t"<<*ins<<"\n";
//                             aci = ((const ArrayType*)aci) ->getElementType();
//                           //  typ->
//                         }
//                          if(aci ->isStructTy())
//                         {
//                              StructType *st = ((StructType*) aci);
//                              int num = st->getNumContainedTypes();
//                              int j;
//                              for(j = 0; j < num; j++)
//                              {
//
//                               size *=   st->getContainedType(j)->getScalarSizeInBits();
//
//
//                              }
//                         }
//                         else//if(aci ->isIntegerTy())
//                         {
//                             size *= 8;
//                         }




                            
                            localoffset += size;

                            //errs()<<"\t\taddress= "<<ins<<"\n";

                            break;
                        }
                        case 28:
                            //errs() << ";executing Store" << "\n";

                        {
                            const PointerType* pt;
                            Value* points;
                   //         bool flag = false;
                            // Value * nwpoints;
                            pt = (const PointerType*) ins->getOperand(1)->getType();

                            points = ins->getOperand(1);
                            if (isa<PointerType > (ins->getOperand(0)->getType())) {
                                // errs()<<"gfbgf\ngfbn\ngfbgfbgfbn\ngfngfn\ngfnn\ngf";


                                pointsto[ins->getOperand(1)] = ins->getOperand(0);


                            }//Get the location of the pointer. First go to the instruction where the pointer is defined and then loops to get the pointing value.
                            else if (isa<PointerType > (ins ->getOperand(1) ->getType())) {

                                int count = 0;

                                while (isa<PointerType > (points->getType()) && valnumtable.find((Instruction*) points) != valnumtable.end()) {

                                    points = valnumtable[(Instruction*) points];

                                    count++;

                                }

                                for (int i = 0; i < count; i++) {
                                    if (pointsto.find(points) == pointsto.end()) {
                                        errs() << ";Undefined pointer\n\n";
                                        cleartables();
                                        //break;
                                    }

                                    points = pointsto[points];
                                }

                            }

                            Value* op = points;
                            string exp; // = new string();
                            //valnumtable[op] = ins;


                            exp.append(op -> getNameStr());
                            //errs()<<"exp = \t"<<exp<<"\n\n";

                            if (hashtable.find(exp) == hashtable.end()) {
                                //hashtable[exp] = ins;
                            } else if (exp.size() > 0)//To skip expressions for temporary variables
                                //For store %a,%b, If b is in hashtable, change its value to %a
                            {

                                //if(((Instruction*)op)->getOpcode() != 29){
                                if (points == ins->getOperand(0)) {
                                    //errs()<<"\n\n\t;Expression "<<exp<<" stored in hash table\n\n";
                                    hashtable[exp] = (Instruction*) ins->getOperand(0);
                                } else {
                                    hashtable.erase(exp);
                                }
                            }

                            Value * v = ins->getOperand(0);
                            // errs() <<" operand in store is "<<*(ins ->getOperand(0))<<"\n";

                            if (valnumtable.find((Instruction*) v) != valnumtable.end()) {
                                Value *name = valnumtable[(Instruction*) v];
                                // errs() << "from valtable " << *name << "\n";
                                if (nametable1.find(name) == nametable1.end()) {
                                    //  nametable1[v] = a;
                                    //nametable2[v] = true;
                                    //errs() << "undefined operand " << *name << "\n";
                                } else {
                                    Value* val = nametable1[name];

                                    //If %a is having a constant value, replace it by the constant value
                                    if (isa<ConstantInt > (val)) {
                                        //    errs() << "is a constant in store\n";
                                        ins->setOperand(0, val);
                                        // ins->replaceAllUsesWith(val);


                                    }
                                    //  errs() << "operand found ********************" << "\n";

                                }
                            }
                            v = ins->getOperand(0);
                            if (isa<ConstantInt > (v)) {
                                if (count < 1) {
                                    //If %a is a constant, enter (%b,a) into nametable1
                                    nametable1[ins ->getOperand(1)] = ins->getOperand(0);
                                } else {
                                    nametable1.erase(ins->getOperand(1));
                                }

                            } else {

                                if (nametable1.find(ins ->getOperand(1)) != nametable1.end()) {
                                    //%a is not constant. So remove the entry of %b from nametable1 if it exists
                                    nametable1.erase(ins->getOperand(1));
                                }


                            }

                        }

                            break;
                        case 27:

                            //errs() << ";executing Load" << "\n";
                        {
                            //For %x = load %a, put (a,%x) in hashtable
                            Value* op = ins ->getOperand(0);
                            string exp; // = new string();

                            exp.append(op -> getNameStr());

                            if (hashtable.find(exp) == hashtable.end()) {
                                if (((Instruction*) op)->getOpcode() != 29) {//Skipping for arrays
                                    // errs() << "\n\nexp= " << exp << "sixeof exp = " << exp.size() << "\n\n";
                                    if (exp.size() > 0) //To skip expressions for temporary variables
                                        hashtable[exp] = ins;
                                } else {
                                    //      errs() << "An array skipped\n";
                                }

                            } else //If a is already in hashtable, load is omitted and all %x are replaced by hashtable[a]
                            {
                                // if (!pflag) {


                                ins->replaceAllUsesWith(hashtable.find(exp)->second);
                                flag = true;

                                //continue;
                            }
                            //if (isa<Instruction > (op))
                            {
                                //errs()<<"inside first if\n";
                                // if (valnumtable.find((Instruction*) op) != valnumtable.end()) {

                                //    errs()<<"inside second if\n";
                                if (globals.find(op) != globals.end()) {
                                    //  errs()<<"inside globals\n";
                                    ins->replaceAllUsesWith(globals[op]);
                                    flag = true;
                                }

                            }


                            //If load instruction is there to stay, add (%x,%a) into valnumtable
                            if (!flag) {
                                valnumtable[ins] = op;
                            }
                            // if(nametable1.find(op) == nametable1.end()) {
                            if (isa<ConstantInt > (op)) {
                                // errs() << "constant in load\n";
                                nametable1[ins] = op;
                            }





                        }

                            break;



                        case 45:
                        {

                            cleartables();
                            break;
                        }
                        case 29:
                            //errs() << ";executing getelementptr" << "\n";
                            break;
                    }
                }


            }
            for (map<string, Instruction*>::iterator it = hashtable.begin(); it != hashtable.end(); it++) {
                //    errs() << it->first << ": " << it->second << "\n";
            }


           // localoffset = 0;
            return true;

        }

        virtual bool runOnFunction(Function & F) {

            //  for (Function::iterator fi = F.begin(); fi != F.end(); fi++) {
            //  runOnBasicBlock(*fi);
            //}

            // if (mi -> getNameStr() == "printf" || mi -> getNameStr() == "puts" || mi -> getNameStr() == "putchar" || mi->getNameStr() == "\01__isoc99_scanf")
                    //                  || !strcmp(name,"__isoc99_scanf"))
              //      continue;
             errs()<<"In function\t"<<F.getNameStr()<<"\n\n";

            offset = 8;
              int argnum = 0;
             // fprintf(f, "\tsubq\t$%d, %%rsp\n", activsize[&F]+80+(F.getArgumentList().size()-6) *8);
              //offset += (F.getArgumentList().size()-6) *8;
                for (Function::arg_iterator ai = F.arg_begin(), end = F.arg_end(); ai != end; ai++, argnum++)
            {
                 Value *arg = ai->getValueName()->getValue();
                    memdescriptor[arg] = offset;
                    if(argnum < 6)
                    {
                        fprintf(f, "\tmovq\t%%%s, -%d(%%rbp)\n",argregs.at(argnum).c_str(),offset);

                        fprintf(stderr, "\tmovq\t%%%s, -%d(%%rbp)\n",argregs.at(argnum).c_str(),offset);
                    }
                    else
                    {
                         fprintf(f, "\tmovq\t%d(%%rbp), %%%s\n",8*(argnum-6+2),"rax");
                         fprintf(f, "\tmovq\t%%%s, -%d(%%rbp)\n","rax",offset);

 fprintf(stderr, "\tmovq\t%d(%%rbp), %%%s\n",8*(argnum-6+2),"rax");
                         fprintf(stderr, "\tmovq\t%%%s, -%d(%%rbp)\n","rax",offset);
                    }
                offset += 8;
             }
              //exit(0);



fprintf(f, "\tsubq\t$%d, %%rsp\n", activsize[&F]+176);


            for (Function::iterator fi = F.begin(); fi != F.end(); fi++) {
                runOnBasicBlockLive(*fi);
            }




            for (Function::iterator fi = F.begin(); fi != F.end(); fi++) {

                fprintf(f,".%s%s:\n",fi->getNameStr().c_str(),F.getNameStr().c_str());
               // exit(0);
                runOnBasicBlockOut(*fi);
            }


            return true;
        }

        virtual bool runOnModule(Module & M) {
            for (Module::iterator mi = M.begin(); mi != M.end(); mi++) {
                localoffset = 0;
                int argnum = 0;

                 if (mi -> getNameStr() == "malloc" || mi -> getNameStr() == "printf" || mi -> getNameStr() == "puts" || mi -> getNameStr() == "putchar" || mi->getNameStr() == "\01__isoc99_scanf")
                    //                  || !strcmp(name,"__isoc99_scanf"))
                    continue;


                for (Function::arg_iterator ai = mi->arg_begin(), end = mi->arg_end(); ai != end; ai++, argnum++)
    {
        //Value *Arg = ai->getValueName()->getValue();
        localoffset += 8;
             }
                for (Function::iterator fi = mi->begin(); fi != mi->end(); fi++) {
                    //do optimizations
                    runOnBasicBlock(*fi);

                }
                activsize[(Value*)mi] = localoffset;
                errs()<<*mi<<"\t"<<"loffset = \t"<<localoffset<<"\n";
                 for (Function::iterator fi = mi->begin(); fi != mi->end(); fi++) {
                    //do optimizations
                    runOnBasicBlockPrint(*fi);
                }
            }
            //exit(0);
            openfile();
            reginit();
            argreginit();
            //docodegen
            for (Module::global_iterator gi = M.global_begin(); gi != M.global_end(); gi++) {





                //errs() << ";Global" << "\n";
                if (gi ->hasInitializer()) {
                    //  errs() << ";has initializer\n";

                    Constant * val = gi ->getInitializer();
                    globals[gi] = gi->getInitializer();
                    if (isa <ConstantInt > (val)) {
                        ConstantInt *ci = dyn_cast<ConstantInt > (val);
                        // errs() << ";" << ci ->getSExtValue() << "\n";
                        //  errs () << (dyn_cast<ConstantInt>(val))->getSExtValue()<<"\n";
                        fprintf(f, ".globl %s\n", gi ->getValueName()->getKey().str().c_str());
                        fprintf(f, "\t.data\n");
                        fprintf(f, "\t.align\t 64\n");
                        fprintf(f, "\t.type\t%s, @object\n", gi ->getValueName()->getKey().str().c_str());
                        fprintf(f, "\t.size\t%s, 8\n", gi ->getValueName()->getKey().str().c_str());
                        fprintf(f, "%s:\n", gi ->getValueName()->getKey().str().c_str());
                        fprintf(f, "\t.long\t%d\n",(int) ci ->getSExtValue());
                    }
                    if (isa <ConstantArray > (val)) {
                        // fprintf(f,"%s:\n",gi ->getValueName()->getKey().str());

                        fprintf(f, ".globl %s\n", gi ->getValueName()->getKey().str().c_str());
                        fprintf(f, "\t.data\n");
                        fprintf(f, "\t.align\t 64\n");
                        fprintf(f, "\t.type\t%s, @object\n", gi ->getValueName()->getKey().str().c_str());


                        fprintf(f, "%s:\n", gi ->getValueName()->getKey().str().c_str());
                        //fprintf(f,"hello\n");
                        //fprintf(f, GV->getValueName()->getKey().str() << ":\n";

                        ConstantArray *ci = dyn_cast<ConstantArray > (val);
                        //      errs() << ";" << *ci << "\t" << ci->getAsString() << "\n";

                        char* name = fixup(ci ->getAsString().c_str());
                        //        errs()<<"After fixup "<<name<<"\n";
                        fprintf(f, "\t.string \"%s\"\n", name);
                        //  errs () << (dyn_cast<ConstantInt>(val))->getSExtValue()<<"\n";
                    }

                    //errs() << val ->getOperand(0) <<"\n";

                }

            }

            for (Module::iterator mi = M.begin(); mi != M.end(); mi++) {
                //  errs()<<"before name = "<< mi->getNameStr().c_str()<<"\n";

                //        errs()<<"name = "<<name<<"\n";
                if (mi -> getNameStr() == "malloc" || mi -> getNameStr() == "printf" || mi -> getNameStr() == "puts" || mi -> getNameStr() == "putchar" || mi->getNameStr() == "\01__isoc99_scanf")
                    //                  || !strcmp(name,"__isoc99_scanf"))
                    continue;

                //char * name = fix(mi->getNameStr().c_str());
                fprintf(f, ".globl %s\n", mi->getNameStr().c_str());

                fprintf(f, "\t.type\t%s  ,@function\n", mi->getNameStr().c_str());
                fprintf(f, "%s:\n", mi->getNameStr().c_str());
              //  fprintf(f, "\t.cfi_startproc\n");
                fprintf(f, "\tpushq\t%%rbp\n");
                //fprintf(f, "\t.cfi_def_cfa_offset 16\n");
                fprintf(f, "\tmovq\t%%rsp, %%rbp\n");
                //fprintf(f, "\t.cfi_offset 6, -16\n");
                //fprintf(f, "\t.cfi_def_cfa_register 6\n");
                fprintf(f, "\tpushq\t%%rbx\n");


               // fprintf(f, "\tsubq\t$%d, %%rsp\n", activsize[(Value*)mi]+80);






                runOnFunction(*mi);


  //fprintf(f, "\tsubq\t$%d, %%rsp\n", activsize[&F]+80+(F.getArgumentList().size()-6) *8);
                fprintf(f, "\taddq\t$%d, %%rsp\n", activsize[(Value*)mi]+176+(mi->getArgumentList().size()-6)*8);
                fprintf(f, "\tpopq\t%%rbx\n");

                fprintf(f, "\tleave\n");
                fprintf(f, "\tret\n");
                //fprintf(f, "\t.cfi_endproc\n");

            }
            closefile();
            return false;
        }




    };
}


char Valuenum::ID = 0;
INITIALIZE_PASS(Valuenum, "valuenum", "Value Num  Pass", false, false);


